Como crear un bloque para subir archivos a la librería de medios (JS) en WordPress

Contents

Introducción

Este tutorial explica, paso a paso y con todo lujo de detalles, cómo crear un bloque de Gutenberg que permita subir o seleccionar archivos y guardarlos en la Biblioteca de Medios de WordPress usando JavaScript (React APIs de WP). Incluye ejemplos de código listos para usar: el PHP necesario para registrar y encolar los scripts del bloque, el JavaScript del bloque (usando MediaUpload y un media frame personalizado) y una alternativa avanzada mediante la REST API para subir archivos directamente. También se tratan seguridad, permisos y buenas prácticas.

Requisitos y buenas prácticas

  • WordPress 5.0 (Gutenberg integrado) o cualquier instalación con soporte de bloques.
  • Conocimientos básicos de JS (ESNext/JSX) y PHP.
  • Uso recomendado de @wordpress/scripts para build (wp-scripts).
  • Comprueba que el usuario que vaya a subir archivos tenga la capacidad upload_files.
  • Usar nonces para llamadas REST seguras (wp_create_nonce(wp_rest)).

Estructura mínima del plugin/proyecto

Ejemplo de estructura recomendada:

  • my-media-block/
    • my-media-block.php (archivo principal del plugin)
    • src/
      • block.js (código del bloque)
    • build/
      • block.js (archivo resultante tras build)
    • package.json

1) Archivo PHP principal: registrar y encolar

En el archivo principal del plugin registramos el script del bloque y pasamos datos útiles (por ejemplo nonce y siteUrl) para llamadas REST. A continuación un ejemplo mínimo.

 wp_create_nonce( wp_rest ),
        siteUrl => get_site_url(),
    ) )

    register_block_type( bmu/media-uploader, array(
        editor_script => bmu-block,
    ) )
}
add_action( init, bmu_register_block )

Render dinámico opcional

Si quieres que el bloque renderice en el frontend a partir de los atributos puedes registrarlo con render_callback. Ejemplo sencillo:

function bmu_render_block( attributes ) {
    id = isset( attributes[mediaId] ) ? intval( attributes[mediaId] ) : 0
    url = isset( attributes[mediaUrl] ) ? esc_url( attributes[mediaUrl] ) : 
    name = isset( attributes[filename] ) ? esc_html( attributes[filename] ) : 

    if ( ! id  ! url ) {
        return 

No hay archivo seleccionado.

} return sprintf( , url, name ? name : Descargar archivo ) } register_block_type( bmu/media-uploader, array( editor_script => bmu-block, render_callback => bmu_render_block, ) )

2) package.json mínimo para build

Si usas @wordpress/scripts, este package.json proporciona scripts para build y start durante el desarrollo.

{
  name: bmu,
  version: 1.0.0,
  scripts: {
    build: wp-scripts build,
    start: wp-scripts start
  },
  devDependencies: {
    @wordpress/scripts: ^24.0.0
  }
}

3) Código del bloque (JS) – ejemplo usando MediaUpload

La forma más sencilla para permitir que un usuario suba o seleccione un archivo es usar el componente MediaUpload de @wordpress/block-editor. Este componente abre la ventana de medios de WP y permite subir o elegir archivos. Al seleccionar devuelve el objeto de adjunto.

import { registerBlockType } from @wordpress/blocks
import { MediaUpload, MediaUploadCheck } from @wordpress/block-editor
import { Button } from @wordpress/components
import { Fragment } from @wordpress/element

registerBlockType( bmu/media-uploader, {
    title: Subir archivo a Media Library,
    category: media,
    attributes: {
        mediaId: { type: number },
        mediaUrl: { type: string },
        filename: { type: string }
    },
    edit: ( { attributes, setAttributes } ) => {
        const { mediaId, mediaUrl, filename } = attributes

        const onSelectMedia = ( media ) => {
            if ( ! media  ! media.id ) return
            setAttributes({
                mediaId: media.id,
                mediaUrl: media.url  media.sizes?.full?.url  media.source_url,
                filename: media.title?.raw  media.filename  
            })
        }

        const removeMedia = () => {
            setAttributes({ mediaId: undefined, mediaUrl: undefined, filename: undefined })
        }

        return (
            
                
{ mediaUrl ? (
{

Archivo: { filename } (ID: { mediaId })

) : ( ( ) } /> ) }
) }, save: () => { return null // se usa render_callback o atributos guardados. } } )

Notas sobre MediaUpload

  • MediaUpload permite que el usuario suba (pestaña Subir archivos) o seleccione de la biblioteca.
  • El objeto devuelto en onSelect contiene id, url/source_url, title, filename, mime_type, sizes, etc.
  • Usa allowedTypes para filtrar tipos MIME (por ejemplo image o [application/pdf]).

4) Alternativa: usar un media frame personalizado (window.wp.media)

Si necesitas más control (por ejemplo configurar estado, multiple, título, botones o escuchar eventos concretos), puedes abrir un frame personalizado con window.wp.media. Este ejemplo abre el modal y obtiene el archivo seleccionado o subido.

// abrir un frame personalizado:
const openMediaFrame = () => {
  const wpMedia = window.wp  window.wp.media
  if ( ! wpMedia ) return

  const frame = wpMedia({
    title: Seleccionar o subir archivo,
    button: { text: Usar este archivo },
    multiple: false
  })

  frame.on( select, () => {
    const selection = frame.state().get(selection).first().toJSON()
    // selection contiene id, url, filename, etc.
    setAttributes({
      mediaId: selection.id,
      mediaUrl: selection.url  selection.source_url,
      filename: selection.title  selection.filename
    })
  })

  frame.open()
}

5) Opción avanzada: subir directamente mediante la REST API (/wp/v2/media)

Si quieres subir el archivo desde el cliente sin usar el modal (por ejemplo arrastrando y soltando un archivo y subirlo automáticamente), usa la ruta /wp/v2/media. Es imprescindible enviar la cabecera X-WP-Nonce para autenticar la petición. En el ejemplo siguiente se asume que en el script hemos inyectado bmuData.nonce y bmuData.siteUrl.

// subir archivo directamente a /wp/v2/media
async function uploadFileDirectly( file ) {
  const form = new FormData()
  form.append( file, file, file.name )

  const response = await fetch( bmuData.siteUrl   /wp-json/wp/v2/media, {
    method: POST,
    headers: {
      X-WP-Nonce: bmuData.nonce
    },
    body: form
  } )

  if ( ! response.ok ) {
    const err = await response.text()
    throw new Error( Error subiendo:    err )
  }

  const json = await response.json()
  // json.id, json.source_url
  return json
}

Puntos importantes sobre la REST API

  • El usuario que realice la subida debe tener la capacidad upload_files.
  • Controla los tipos MIME y tamaños en el servidor si es necesario.
  • Comprueba y gestiona errores (código 400/403/413, etc.).

6) Guardar atributos y renderizado

Recomendación: guarda en los atributos al menos mediaId (ID del adjunto) y mediaUrl (URL). El ID permite realizar operaciones adicionales (por ejemplo actualizar la información del adjunto). Para el frontend puedes usar render_callback en PHP (ver ejemplo de PHP arriba) o guardar un HTML estático en save().

7) Permisos, seguridad y validaciones

  • Usa nonces: genera con wp_create_nonce(wp_rest) y pásalo con wp_localize_script para las llamadas REST.
  • Comprueba capacidades del usuario (current_user_can(upload_files)) si haces lógica en PHP.
  • Valida los tipos MIME y tamaños en el servidor (no confíes solo en el cliente).
  • Escapa salidas en PHP con esc_url() / esc_html() si renderizas en el servidor.

8) Errores comunes y cómo solucionarlos

  1. El modal no se abre: asegúrate de que window.wp.media está cargado en editor debe estar presente si las dependencias están bien encoladas.
  2. 403 en la subida REST: nonce inválido o falta capacidad revisa X-WP-Nonce y current_user_can.
  3. URL incorrecta tras seleccionar: revisa las propiedades del objeto devuelto (source_url, url, sizes).
  4. Permisos CORS en instalaciones headless: tendrás que configurar cabeceras o auth adecuada.

9) Tips finales y mejoras

  • Soporta múltiples archivos configurando multiple={true} y guardando un array de IDs/URLs.
  • Muestra previsualizaciones usando los tamaños disponibles en media.sizes.
  • Permite reordenar y eliminar archivos si es una galería/colección.
  • Considera crear un control personalizado que combine drag drop subida vía REST y posterior selección por ID.
  • Versiona y cachea correctamente el script en PHP usando filemtime para busting en producción.

Recapitulación rápida

  • La forma más simple: usar MediaUpload para abrir la ventana de medios (soporta subida automática).
  • Para control extra: usar window.wp.media para crear frames personalizados.
  • Para subir sin UI: usar la ruta REST /wp/v2/media con nonce y FormData.
  • Siempre valida permisos y escapa las salidas cuando renderices en el frontend.

Enlaces útiles

Conclusión

Con estas piezas tienes todo lo necesario para crear un bloque de Gutenberg que permita subir y seleccionar archivos en la Biblioteca de Medios mediante JS. Elige la aproximación (MediaUpload, media frame personalizado o REST API) que mejor se adapte a tu caso de uso, y aplica las comprobaciones de seguridad y validaciones descritas para garantizar robustez en producción.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *